async/await
是 Promise
的語法糖,最主要是提升了 Promise
在鏈式寫法的可讀性,而 async/await
能辦到的 Promise
本身都能辦到,所以不少教學都提到要先明白 Promise
,才會看懂 async/await
。
async
直接翻譯成中文是異步,也就是非同步的意思,若要使用 async
會將 async
放在函式旁,代表這個函式接下來會以同步方式來執行非同步的語法。
await
翻譯成中文,則是等待, 一般是放在 async
函式中的 Promise
事件旁,代表接下來的程式碼會等待 await
方法完成後才執行。
而 async/await
他們算是一組的,基本上使用碰上使用時機時,這兩個方法都會同時被使用 ,這部分用文字說明可能不是這麼好懂,直接來使用 Promise 章節提到的 Promise
鏈式寫法,以及 async/await
來做對比會比較好理解:
Promise
鏈式寫法:const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
PromiseFn('Ryder')
.then((res) => {
console.log(res) // Promise 成功, Ryder 共 5 個字
return PromiseFn('youtube')
}).then((res) => {
console.log(res) // Promise 成功, youtube 共 7 個字
return p
}).then((res) => {
console.log(res) // 直接執行 Promise
})
async/await
則可寫成:const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
async function usePromise() {
const data1 = await PromiseFn('Ryder');
console.log(data1) // Promise 成功, Ryder 共 5 個字
const data2 = await PromiseFn('youtube');
console.log(data2) // Promise 成功, youtube 共 7 個字
const data3 = await p
console.log(data3); // 直接執行 Promise
}
usePromise();
扣掉 console.log
可以發現 async/await
的寫法省去大量的 then()
,因此讓程式碼變的較容易閱讀。
而 await
其實可以塞入其他表達式的,但是實做中通常不會這麼使用:
const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
async function usePromise() {
const data1 = await 1+1;
console.log(data1) // 2
const data2 = await PromiseFn('youtube');
console.log(data2) // Promise 成功, youtube 共 7 個字
const data3 = await p
console.log(data3); // 直接執行 Promise
}
usePromise();
使用 async/await
的寫法 ,只要使用 await
的 Promise
只要一失敗,接下來會回傳 Promise
的 reject
資料,接著 await
下的程式碼都不會被執行,比如:
const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
async function usePromise() {
const data1 = await PromiseFn('Ryder');
console.log(data1) // Promise 成功, Ryder 共 5 個字
const data2 = await PromiseFn('test');
console.log(data2) // Promise 失敗
const data3 = await p
console.log(data3);
}
usePromise();
這種狀況會容易造成不清楚錯誤來源,在維護上會較為困難,也因此 async/await
的寫法,有提供另一種將 Promise
執行成功、失敗分開的寫法,就是 try…catch
,try
專門存放執行 Promise
成功的結果,而 catch
則是執行 Promise
失敗的結果,這個方法跟原生 Promise
的 .then()
、 .catch()
十分相似,如範例:
const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
async function usePromise() {
try{
const data1 = await PromiseFn('Ryder');
console.log(data1) //Promise 成功, Ryder 共 5 個字
const data2 = await PromiseFn('test'); // Promise 執行 catch
console.log(data2)
const data3 = await p
console.log(data3);
}
catch (err) {
console.log('catch', err); //catch Promise 失敗
}
}
usePromise();
要注意的是 try
中的 Promise
執行失敗,是會執行 catch
中的程式碼,而 try
中的程式碼一樣不會繼續執行下去。
一開始有提到 async/await
是 Promise
的語法糖,因此 async/await
其實以可以和 Promise.all
、 Promise.race
一同使用,這也算是目前比較常用再處理 Ajax 處理順序的寫法:
const p = new Promise((resolve) => {
if (true) {
resolve(`直接執行 Promise`)
}
})
function PromiseFn(String) {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (String.length >= 5) {
resolve(`Promise 成功, ${String} 共 ${String.length} 個字 `)
} else {
reject('Promise 失敗')
}
}, 2000);
});
}
async function usePromise() {
const data1 = await Promise.all([PromiseFn('Ryder'), PromiseFn('youtube')])
console.log(data1) // ['Promise 成功, Ryder 共 5 個字 ', 'Promise 成功, youtube 共 7 個字 ']
const data2 = await p
console.log(data2) // '直接執行 Promise'
}